# -*-coding:utf-8-*-

import functools
import time, json, hashlib
import settings
from tornado.gen import coroutine, Return
from tornado.concurrent import Future


def sign_arguments(arguments):
    keys = arguments.keys()
    keys.sort()
    arguments_string = ''
    for key in keys:
        arguments_string += key + str(arguments[key])
    secret = settings.APPS[arguments['appkey']]['secret']
    m = hashlib.md5()
    m.update(secret + arguments_string + secret)
    arguments['sign'] = m.hexdigest().upper()


# TODO: 考虑异步实现，参考 auth.py
def _signed(sign_from_body=True):
    def sign_check_decorator(method):
        @functools.wraps(method)
        def wrapper(self, *args, **kwargs):
            arguments = {}
            if sign_from_body:
                arguments = json.loads(self.request.body)
            else:
                for key, value in self.request.query_arguments.iteritems():
                    if 'utest' != key: arguments[key] = value[0]
            if not self.is_keys_required_present(['sign', 'appkey', 'timestamp'], arguments.keys(), equal=False):
                return
            if not settings.APPS.has_key(arguments['appkey']):
                return self.respond_error('invalid_app_key')
            utest = int(self.get_argument('utest', 0))
            sign_timeout = settings.API_SIGN_TIMEOUT
            if 1 == utest: sign_timeout = settings.TEST_API_SIGN_TIMEOUT
            if int(time.time()) - int(arguments['timestamp']) > sign_timeout:
                return self.respond_error('sign_expired')
            sign = arguments['sign']
            del arguments['sign']
            sign_arguments(arguments)
            if arguments['sign'] != sign:
                return self.respond_error('invalid_sign')
            self.appkey = arguments['appkey']
            self.app_id = settings.APPS[arguments['appkey']]['app_id']
            self.app = self.apps_dao.get_app(arguments['appkey'])
            return method(self, *args, **kwargs)

        return wrapper

    return sign_check_decorator


# 仅从请求中提取必要信息，如 appkey，不真正检查接口签名
def signed(sign_from_body=True):
    def sign_check_decorator(method):
        @functools.wraps(method)
        @coroutine
        def wrapper(self, *args, **kwargs):
            arguments = {}
            if sign_from_body:
                arguments = json.loads(self.request.body)
            else:
                for key, value in self.request.query_arguments.iteritems():
                    if 'utest' != key: arguments[key] = value[0]
            self.appkey = arguments['appkey']
            self.app = yield self.apps_dao.get_app(self.appkey)
            self.app_id = self.app.id_str
            result = method(self, *args, **kwargs)
            if isinstance(result, Future):
                result = yield result
            raise Return(result)

        return wrapper

    return sign_check_decorator
